#include "app_buffer.h"
#define MAX_MESSAGE_SIZE 255
typedef struct
{
    char *ptr;    // 数据指针
    int capacity; // 容量
    int len;      // 数据长度
} sub_buffer_t;
typedef struct
{
    sub_buffer_t *sub_buffer[2]; // 子缓冲区 (双缓冲区) 指针数组
    int read_index;              // 读索引
    int write_index;             // 写索引
    pthread_mutex_t read_mutex;  // 读锁
    pthread_mutex_t write_mutex; // 写锁
} buffer_t;

/**
 * @brief
 *
 * @param capacity
 * @return Com_State
 */
static sub_buffer_t *sub_buffer_init(int capacity)
{
    sub_buffer_t *sub_buffer = (sub_buffer_t *)malloc(sizeof(sub_buffer_t));
    sub_buffer->ptr = (char *)calloc( capacity, sizeof(char) );
    sub_buffer->capacity = capacity;
    sub_buffer->len = 0;
    return sub_buffer;
}
//因为有两个双缓冲区,我们没必要全局定义两次
buffer_handle_t app_buffer_init(int capacity)
{
    buffer_t *buffer = (buffer_t *)malloc(sizeof(buffer_t));
    buffer->sub_buffer[0] = sub_buffer_init(capacity);
    buffer->sub_buffer[1] = sub_buffer_init(capacity);
    buffer->read_index = 0;  // 默认第一个子缓冲区为读缓冲区
    buffer->write_index = 1; // 默认第二个子缓冲区为写缓冲区
    // 锁初始化
    pthread_mutex_init(&buffer->read_mutex, NULL);
    pthread_mutex_init(&buffer->write_mutex, NULL);
    return (buffer_handle_t)buffer;
}

void app_buffer_deinit(buffer_handle_t buffer_handle)
{
    buffer_t *buffer = (buffer_t *)buffer_handle;
    free(buffer->sub_buffer[0]->ptr);
    free(buffer->sub_buffer[0]);
    free(buffer->sub_buffer[1]->ptr);
    free(buffer->sub_buffer[1]);
    free(buffer);
    pthread_mutex_destroy(&buffer->read_mutex);
    pthread_mutex_destroy(&buffer->write_mutex);
}

Com_State app_buffer_write(buffer_handle_t buffer_handle, char *data, int data_len)
{
    // 如果要写入数据长度大于一个消息的最大长度，则返回错误 , 该步骤其实不要也行
    if (data_len > MAX_MESSAGE_SIZE)
    {
        log_error("数据长度超过消息数据的最大长度");
        return COM_ERROR;
    }
    buffer_t *buffer = (buffer_t *)buffer_handle;
    pthread_mutex_lock(&buffer->write_mutex);
    sub_buffer_t *write_buffer = buffer->sub_buffer[buffer->write_index];
    // 判断缓冲区是否已满,如果满了,直接返回, +1是因为第一个字节用于保存数据长度
    if (write_buffer->len + data_len + 1 > write_buffer->capacity)
    {
        log_error("写缓冲区已满,需要空间%d,剩余空间%d", data_len + 1, write_buffer->capacity - write_buffer->len);
        pthread_mutex_unlock(&buffer->write_mutex);
        return COM_ERROR;
    }
    write_buffer->ptr[write_buffer->len] = data_len;                   // 第一个字节保存数据长度
    memcpy(write_buffer->ptr + write_buffer->len + 1, data, data_len); // 写入数据
    write_buffer->len += data_len + 1;
    pthread_mutex_unlock(&buffer->write_mutex);
    log_debug("写入数据成功,数据长度%d, 数据：%.*ss", data_len+1, data_len, data);
    return COM_OK;
}

static void swap_buffer(buffer_t *buffer)
{
    //加写锁 , 如果当前正在写数据,则等待写完再交换, 否则数据完整性丢失
    pthread_mutex_lock(&buffer->write_mutex);
    int temp = buffer->write_index;
    buffer->write_index = buffer->read_index ;
    buffer->read_index =  temp;
    pthread_mutex_unlock(&buffer->write_mutex);
    log_debug("交换缓冲区成功,当前读缓冲区为%d,当前写缓冲区为%d", buffer->read_index, buffer->write_index);   
}

// 读缓冲区
int app_buffer_read(buffer_handle_t buffer_handle, char *read_data, int buff_len)
{
    buffer_t *buffer = (buffer_t *)buffer_handle;
    pthread_mutex_lock(&buffer->read_mutex);
    sub_buffer_t *read_buffer = buffer->sub_buffer[buffer->read_index];
    // 如果缓冲区为空,则切换到另一个缓冲区
    if (read_buffer->len == 0)
    {

        swap_buffer(buffer);
        read_buffer = buffer->sub_buffer[buffer->read_index];
        if (read_buffer->len == 0)
        {
            log_error("缓冲区为空");
            pthread_mutex_unlock(&buffer->read_mutex);
            return -1; 
        }
    }
    int data_len = read_buffer->ptr[0];
    //如果 提供的buffer容量 小于 实际数据长度 , 返回错误
    if (data_len > buff_len)
    {
        log_error("提供的缓冲区容量:%d,小于实际数据长度:%d" , buff_len, data_len);
        pthread_mutex_unlock(&buffer->read_mutex);
        return -1;
    }
    memcpy(read_data, read_buffer->ptr + 1, data_len);
    //移除读缓冲区第一个数据帧(将后面的数据前移)
    memmove(read_buffer->ptr, read_buffer->ptr + data_len + 1, read_buffer->len - data_len - 1);
    read_buffer->len -= data_len + 1;
    pthread_mutex_unlock(&buffer->read_mutex);
   
    log_debug("读取数据成功,数据长度%d, 数据：%.*s", data_len, data_len, read_data);
    return data_len;
}